# -*- coding: utf-8 -*-
"""
缓存工具类
提供统一的缓存接口，支持Redis和内存缓存
"""

import json
import hashlib
from typing import Any, Optional, Union
from functools import wraps
from flask import current_app
import redis


class CacheManager:
    """缓存管理器"""
    
    def __init__(self):
        self._redis_client = None
        self._cache_type = 'simple'  # simple 或 redis
    
    @property
    def redis_client(self):
        """获取Redis客户端"""
        if self._redis_client is None:
            try:
                redis_url = current_app.config.get('REDIS_URL', 'redis://localhost:6379/0')
                self._redis_client = redis.from_url(redis_url)
                # 测试连接
                self._redis_client.ping()
                self._cache_type = 'redis'
            except Exception as e:
                current_app.logger.warning(f"Redis连接失败，使用内存缓存: {e}")
                self._cache_type = 'simple'
        return self._redis_client
    
    def _generate_key(self, prefix: str, *args, **kwargs) -> str:
        """生成缓存键"""
        key_parts = [prefix]
        
        # 添加位置参数
        for arg in args:
            key_parts.append(str(arg))
        
        # 添加关键字参数
        for key, value in sorted(kwargs.items()):
            key_parts.append(f"{key}:{value}")
        
        key_string = ":".join(key_parts)
        return hashlib.md5(key_string.encode()).hexdigest()
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取缓存值"""
        try:
            if self._cache_type == 'redis':
                value = self.redis_client.get(key)
                if value is not None:
                    return json.loads(value)
            else:
                # 简单的内存缓存（生产环境建议使用Redis）
                return getattr(self, f'_cache_{key}', default)
        except Exception as e:
            current_app.logger.error(f"获取缓存失败: {e}")
        return default
    
    def set(self, key: str, value: Any, timeout: int = 300) -> bool:
        """设置缓存值"""
        try:
            if self._cache_type == 'redis':
                return self.redis_client.setex(
                    key, 
                    timeout, 
                    json.dumps(value, ensure_ascii=False)
                )
            else:
                # 简单的内存缓存
                setattr(self, f'_cache_{key}', value)
                return True
        except Exception as e:
            current_app.logger.error(f"设置缓存失败: {e}")
        return False
    
    def delete(self, key: str) -> bool:
        """删除缓存"""
        try:
            if self._cache_type == 'redis':
                return bool(self.redis_client.delete(key))
            else:
                # 简单的内存缓存
                if hasattr(self, f'_cache_{key}'):
                    delattr(self, f'_cache_{key}')
                return True
        except Exception as e:
            current_app.logger.error(f"删除缓存失败: {e}")
        return False
    
    def clear_pattern(self, pattern: str) -> int:
        """清除匹配模式的缓存"""
        try:
            if self._cache_type == 'redis':
                keys = self.redis_client.keys(pattern)
                if keys:
                    return self.redis_client.delete(*keys)
            # 内存缓存不支持模式删除
        except Exception as e:
            current_app.logger.error(f"清除缓存失败: {e}")
        return 0


# 全局缓存实例
cache_manager = CacheManager()


def cached(prefix: str, timeout: int = 300):
    """
    缓存装饰器
    :param prefix: 缓存键前缀
    :param timeout: 缓存超时时间（秒）
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = cache_manager._generate_key(prefix, *args, **kwargs)
            
            # 尝试从缓存获取
            cached_result = cache_manager.get(cache_key)
            if cached_result is not None:
                return cached_result
            
            # 执行函数
            result = func(*args, **kwargs)
            
            # 缓存结果
            cache_manager.set(cache_key, result, timeout)
            
            return result
        return wrapper
    return decorator


def invalidate_cache(prefix: str):
    """
    缓存失效装饰器
    :param prefix: 要失效的缓存键前缀
    """
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 执行函数
            result = func(*args, **kwargs)
            
            # 清除相关缓存
            pattern = f"{prefix}:*"
            cache_manager.clear_pattern(pattern)
            
            return result
        return wrapper
    return decorator 